package com.ybear.ybnetworkutil.http;

import android.app.Application;
import android.util.Log;

import androidx.annotation.NonNull;

import com.ybear.ybnetworkutil.annotations.ReCountTrigger;
import com.ybear.ybnetworkutil.call.CallReqAdapter;
import com.ybear.ybnetworkutil.call.Callback;
import com.ybear.ybnetworkutil.queue.HttpQueue;
import com.ybear.ybnetworkutil.queue.Queue;
import com.ybear.ybnetworkutil.request.Method;
import com.ybear.ybnetworkutil.request.Request;

import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import okhttp3.Call;
import okhttp3.Response;

/**
 * Http重连机制
 * 主要用于当请求失败时且在某个范围内（重试次数）重新提交请求数据，直至请求成功。
 *
 * 使用姿势：
 * {@link HttpClient#setHttpReboot(HttpReboot)}
 *
 *
 * 触发器
 * {@link HttpTrigger}
 * 用于监听网络状态等操作{@link ReCountTrigger}，设置的条件满足后会调用 {@link #reAsync(Request)} 重新
 * 发起请求操作。
 *
 * 队列操作
 * {@link #addDoQueue(Request)}
 * {@link #removeDoQueue(Request)}
 * 成功/失败的请求会通过它添加/移除队列，失败的请求，同时增加重试次数和回调 {@link Callback} 。
 */
public class HttpReboot implements HttpTrigger.TriggerListener {
    private final ExecutorService mPool = Executors.newFixedThreadPool( 1 );
    private final HttpQueue mQueue;                     //请求队列
//    private final AtomicInteger mAsyncReCount;          //当前重试次数（重试时自增，成功或失败时自减）
    private HttpTrigger mTrigger;                       //触发器
    private Req mReq;                                   //请求设置
    private CallReqAdapter mCallReqAdapter;             //监听请求

    private HttpReboot() {
        mQueue = new HttpQueue();
//        mAsyncReCount = new AtomicInteger( 0 );
    }
    public static HttpReboot get() { return HANDLER.I; }
    private static class HANDLER { private static final HttpReboot I = new HttpReboot();}

    public HttpReboot init(Application app) {
        mTrigger = HttpTrigger.get().init( app );
        mTrigger.setTriggerListener( this );
        return this;
    }

    void initReq(@NonNull Req req) {
        mReq = req;
        mCallReqAdapter = new CallReqAdapter() {
            private Request mRequest;

            @Override
            public void onRequest(@NonNull Request r) {
                super.onRequest(r);
                mRequest = r;
            }
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                super.onFailure(call, e);
                //请求失败后添加至处理队列
                addDoQueue( mRequest );
            }
            @Override
            public void onResponse(@NonNull Call call, @NonNull Response r) throws IOException {
                super.onResponse(call, r);
                //请求成功后移除出处理队列
                removeDoQueue( mRequest );
            }
        };
        mReq.addReqDataListener( mCallReqAdapter );
    }

    /**
     * 释放管理器
     */
    public void release() {
        if( mTrigger != null ) {
            mTrigger.release();
            mTrigger = null;
        }
        mQueue.release();
        if( mReq != null ) {
            mReq.removeReqDataListener( mCallReqAdapter );
        }
    }

    /**
     * 重新发起异步请求
     * 发起请求会根据Method的类型调用不同的异步请求
     * @param request    请求实体
     */
    private void reAsync(@NonNull Request request) {
        //重试次数不能超过设置的最大值
        if( request.getCurrentReCount() >= request.getMaxReCount() ) {
            request.setCurrentReCount( 0 );
            return;
        }
        Log.d("MAIN_TAG", "size:" + request.getCurrentReCount() );
//        //递增一次重发次数
//        mAsyncReCount.incrementAndGet();
        //创建请求
        ClientBuilder clientBuilder = mReq.req( request );
        //发起请求
        switch ( request.getMethod() ) {
            case Method.GET:
                clientBuilder.get();
                break;
            case Method.POST:
                clientBuilder.post();
                break;
            case Method.HEAD:
                clientBuilder.head();
                break;
            case Method.PUT:
                clientBuilder.put();
                break;
            case Method.PATCH:
                clientBuilder.patch();
                break;
            case Method.DELETE:
                clientBuilder.delete();
                break;
        }
    }

    /**
     * 请求失败后添加至处理队列
     * @param request   实体
     */
    private void addDoQueue(@NonNull Request request) {
        Log.d("MAIN_TAG", "addDoQueue -> " + request);
        int currentReCount;
        //启动触发器
        mTrigger.start();
        //加入处理队列
        request = mQueue.addDoQueue( request );
        //返回 null 表示已从队列中移除，则不需要增加重连次数
        if( request == null ) return;
        //当前请求的重试次数
        currentReCount = request.getCurrentReCount();
        if( currentReCount > 0 ) request.decrementCurrentReCount();
//        //减少一次重发次数
//        if( currentReCount > 0 && mAsyncReCount.get() > 0 ) mAsyncReCount.decrementAndGet();
    }

    /**
     * 请求成功后移除出处理队列
     * @param request   实体
     */
    private void removeDoQueue(@NonNull Request request) {
        int currentReCount;
        //移除处理队列
        request = mQueue.removeDoQueue( request );
        //当前请求的重试次数
        currentReCount = request.getCurrentReCount();
        if( currentReCount > 0 ) request.decrementCurrentReCount();
//        //减少一次重发次数
//        if( currentReCount > 0 && mAsyncReCount.get() > 0 ) mAsyncReCount.decrementAndGet();
        //处理存在成功请求的操作
        mTrigger.doExistResponse();
    }

    /**
     * 触发器
     * 触发条件满足后执行队列中失败的请求
     */
    @Override
    public void trigger() {
        Queue queue = mQueue.getQueue();
//        if( queue.size() > 0 && mAsyncReCount.get() > 0 ) return;
        mPool.execute(() -> {
            //处理失败的请求
            for( Request val : mQueue.values() ) {
                if (val != null) reAsync( val );
            }
        });
    }

//    /**
//     * 请求转换为请求实体
//     * @param url           请求链接
//     * @param param         请求参数
//     * @param mCallback     回调接口
//     * @param mMaxReCount    最大重试次数
//     * @return              请求实体
//     */
//    private Request formatRequest(final @NonNull String url,
//                                      @Nullable Map<String, Object> param,
//                                      @Nullable Callback mCallback, int mMaxReCount) {
//        Request request = new Request() {
//            @Override
//            public String url() { return url; }
//            @Override
//            public String api() { return null; }
//        };
//        request.setCallback( mCallback );
//        request.setMaxReCount( mMaxReCount );
//        request.getParam().addParamAll( param );
//        return request;
//    }

    /**
     * 获取处理队列
     * @return  处理队列
     */
    public Queue getQueue() { return mQueue.getQueue(); }

//    /**
//     * 获取最大重试次数
//     * @return  重试次数
//     */
//    public int getMaxReCount() { return mCallReqAdapter.getClass().getMaxReCount(); }
//
//    /**
//     * 设置最大重试次数
//     * @param count         最大重试次数
//     * @return              {@link HttpReboot}
//     */
//    public HttpReboot setMaxReCount(int count) {
//        mRequestAuto.setMaxReCount( count );
//        return this;
//    }

    /**
     * 设置触发器条件
     * @param triggers  条件
     *                  网络可用时触发 {@link ReCountTrigger#NETWORK_AVAILABLE}
     *                  网络切换时触发 {@link ReCountTrigger#NETWORK_SWITCH}
     *                  存在发起请求并且成功响应时触发 {@link ReCountTrigger#EXIST_RESPONSE}
     * @return          {@link HttpReboot}
     */
    public HttpReboot setTriggers(@ReCountTrigger String... triggers) {
        mTrigger.setReCountTrigger( triggers );
        return this;
    }
}
